#include "hiddevice.h"
#include <QVariant>
#include <linux/hidraw.h>
#include <QDebug>
#include <dirent.h>

// HIDIOCGINPUT and HIDIOCSOUTPUT are not defined in Linux kernel headers < 5.11.
// These definitions are from hidraw.h in Linux >= 5.11.
// https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=f43d3870cafa2a0f3854c1819c8385733db8f9ae
#ifndef HIDIOCGINPUT
#define HIDIOCGINPUT(len)    _IOC(_IOC_WRITE|_IOC_READ, 'H', 0x0A, len)
#endif
#ifndef HIDIOCSOUTPUT
#define HIDIOCSOUTPUT(len)   _IOC(_IOC_WRITE|_IOC_READ, 'H', 0x0B, len)
#endif

//void HidDevice::findDevices(QMap<QString,HidDevice*>& hidDevices)
//{
//    DIR* dir = opendir("/dev/usb/");
//    if(dir == nullptr){
//        qDebug("opendir failed");
//        //return 0;
//        return;
//    }

//    struct dirent* ptr = nullptr;
//    struct hiddev_devinfo info;
//    int ret = 0;
//    char name[1024];
//    while((ptr = readdir(dir))){
//        if(strcmp(".",ptr->d_name)==0 || strcmp("..",ptr->d_name)==0)
//            continue;
//        if(hidDevices.contains(ptr->d_name))  //重复open会修改fd的值,导致原来在容器中的fd失效
//            continue;
//        QString path("/dev/usb/");
//        path.append(ptr->d_name);
//        qDebug()<<"devPath:"<<path;
//        int fd = open(path.toStdString().c_str(),O_RDWR | O_CLOEXEC);
//        if(fd < 0){
//            qDebug("open error");
//            continue;
//        }

//        if(ioctl(fd,HIDIOCGDEVINFO,&info) == -1){
//            qDebug("HIDIOCGDEVINFO,error");
//            //return -1;
//            continue;
//        }
//        qDebug("HIDIOCGDEVINFO applicationNum:%d",info.num_applications);

//        ret = 0;
//        //查找usb设备应用中是否有TELEPHOY_HEADSET(hookOff和mute功能等)设备和consumer(音量控制)设备
//        for(unsigned int i=0; i!=info.num_applications; i++){
//            unsigned usage = ioctl(fd,HIDIOCAPPLICATION,i);
//            if((int)usage == -1){
//                qDebug("HIDIOCAPPLICATION error");
//                //return -2;
//                break;
//            }
//            if(((unsigned short)(usage) == HID_USAGE_TELEPHOY_HEADSET || (unsigned short)(usage) == HID_USAGE_TELEPHOY_HANDSET) && ((unsigned short)(usage >> 16) == HID_USAGE_PAGE_TELEPHOY)){ //buttonDevice
//                ret++;
//                qDebug("find telephony application");
//                continue;
//            }
//            if(((unsigned short)(usage) == HID_USAGE_CONSUMERCTRL) && ((unsigned short)(usage >> 16)  == HID_USAGE_PAGE_CONSUMER)){ //volumeDevice
//                ret++;
//                qDebug("find volume application");
//                continue;
//            }
//            qDebug("usages of application[%u]: %0x\n",i,usage);
//        }

//        if(ret != 2) continue;

//        memset(name,0,sizeof(name));
//        ioctl(fd,HIDIOCGNAME(sizeof(name)),name);

//        auto dev = new HidDevice(fd);
//        //emit newDevice(QString(name),dev);
//        hidDevices[ptr->d_name] = dev;
//    }

//    closedir(dir);
////    if(m_pSockNotifier == nullptr){
////        setupNotifier();
////    }
////    return m_hidDevices.size();
//}

HidDevice::HidDevice(int fd, QObject *parent)
    : QObject(parent)
    , m_iHandle(fd)
{
    m_stateMute = false;
    m_stateOffHook = false;
    m_stateFlash = false;

    getReportId();
    setRWFlags();

    timer.setSingleShot(true);
    connect(this,&HidDevice::sigTimerStart,this,[this](int key){
        timer.stop();
        timer.start(1000);
        timer.setProperty("KeyVal",key);
    });
    connect(&timer,&QTimer::timeout,this,&HidDevice::handleTimeOut);
}

HidDevice::~HidDevice()
{
    qDebug("device close");
    close(m_iHandle);
}

#include <libusb.h>

bool HidDevice::getReportId()
{
    //遍历usb设备输入输出集
    struct hiddev_report_info rinfo ={
        .report_type = HID_REPORT_TYPE_INPUT,
        .report_id = HID_REPORT_ID_FIRST
    };
    struct hiddev_field_info finfo;
    struct hiddev_usage_ref uref;
    int num = 0;    //标记找到的reportId数量,起码要找到mute,offHook以及对应的led,还有音量加减

begin_traversal:
    while(ioctl(m_iHandle, HIDIOCGREPORTINFO, &rinfo) >= 0){
        qDebug("reportType:%d,reportId:%d,numfields:%d",rinfo.report_type,rinfo.report_id,rinfo.num_fields);

        for (unsigned int i = 0; i < rinfo.num_fields; i++) {
            finfo.report_type = rinfo.report_type;
            finfo.report_id = rinfo.report_id;
            finfo.field_index = i;
            ioctl(m_iHandle, HIDIOCGFIELDINFO, &finfo);
            qDebug("\nfinfoMaxUsages:%d",finfo.maxusage);
            qDebug("finfo,Reportype:%d,reportId:%d,filedIndex:%d,flags:%d,application:%d,unit:%d",
                   finfo.report_type,finfo.report_id,finfo.field_index,finfo.flags,finfo.application,finfo.unit);

            for (unsigned int j = 0; j < finfo.maxusage; j++) {
                uref.report_type = rinfo.report_type;
                uref.report_id = rinfo.report_id;
                uref.field_index = i;
                uref.usage_index = j;
                ioctl(m_iHandle, HIDIOCGUCODE, &uref);  //usage_code
                ioctl(m_iHandle, HIDIOCGUSAGE, &uref);  //usage_index
                qDebug("urefusage_code:%x",uref.usage_code);                
                if(uref.usage_code == (HID_USAGE_PAGE_TELEPHOY << 16 | HID_USAGE_TELEPHOY_HOOK_SWITCH)){
                    m_reportIdHookSwitch_In = uref.report_id;
                    qDebug("find hookswitch simulate reportId:%d",m_reportIdHookSwitch_In);
                    num++;
                }else if(uref.usage_code == (HID_USAGE_PAGE_LED <<16 | HID_USAGE_LED_OFF_HOOK)){
                    m_reportIdOffHook_Out = uref.report_id;
                    m_ledOffHookEv = uref;
                    qDebug("find hookswitch repeat reportId:%d",m_reportIdOffHook_Out);
                    num++;
                }else if(uref.usage_code == (HID_USAGE_PAGE_TELEPHOY << 16 | HID_USAGE_TELEPHOY_MUTE)){
                    m_reportIdMute_In = uref.report_id; 
                    qDebug("find mute simulate reportId:%d",m_reportIdMute_In);
                    qDebug("mute value:%d",uref.value);
                    num++;
                }else if(uref.usage_code == (HID_USAGE_PAGE_LED <<16 | HID_USAGE_LED_MUTE)){
                    m_reportIdMute_Out = uref.report_id;
                    m_ledMuteEv = uref;
                    qDebug("find mute repeat reportId:%d",m_reportIdMute_Out);
                    num++;
                }else if(uref.usage_code == (HID_USAGE_PAGE_TELEPHOY << 16 | HID_USAGE_TELEPHOY_FLASH)){
                    m_reportIdFlash_In = uref.report_id;;
                    qDebug("find flash simulate reportId:%d",m_reportIdFlash_In);
                    num++;
                }else if(uref.usage_code == (HID_USAGE_PAGE_LED << 16 | HID_USAGE_LED_HOLD)){
                    m_reportIdFlash_Out = uref.report_id;
                    m_ledFlashEv = uref;
                    qDebug("find flash repeat reportId:%d",m_reportIdFlash_Out);
                    num++;
                }else if(uref.usage_code == (HID_USAGE_PAGE_LED << 16 | HID_USAGE_LED_RING)){
                    m_reportIdRing_Out = uref.report_id;
                    m_ledRingEv = uref;
                    qDebug("find ring repeat reportId:%d",m_reportIdRing_Out);
                    num++;
                }else if(uref.usage_code == (HID_USAGE_PAGE_CONSUMER << 16 | HID_USAGE_CONSUMER_VOLUME_INCREMENT)){
                    m_reportIdVolumeInc_In = uref.report_id;
                    m_volumeUpEv = uref;
                    qDebug("find volumeUp repeat reportId:%d",m_reportIdVolumeInc_In);
                    num++;
                }else if(uref.usage_code == (HID_USAGE_PAGE_CONSUMER << 16 | HID_USAGE_CONSUMER_VOLUME_DECREMENT)){
                    m_reportIdVolumeDec_In = uref.report_id;
                    m_volumeDownEv = uref;
                    qDebug("find volumeDown repeat reportId:%d",m_reportIdVolumeDec_In);
                    num++;
                }
            }
        }
        rinfo.report_id |= HID_REPORT_ID_NEXT;
    }
    if(rinfo.report_type == HID_REPORT_TYPE_INPUT){
        rinfo.report_type = HID_REPORT_TYPE_OUTPUT;
        rinfo.report_id = HID_REPORT_ID_FIRST;
        goto begin_traversal;
    }
    return num >= 6 ? true : false;
}

void HidDevice::sendVolumeEnd()
{
    struct hiddev_usage_ref uref;
    struct hiddev_report_info rinfo;
    uref.report_type = HID_REPORT_TYPE_OUTPUT;
    rinfo.report_type = HID_REPORT_TYPE_OUTPUT;
    uref = m_volumeDownEv;
    uref.report_id = m_reportIdVolumeDec_In;
    uref.value = 0;
    rinfo.report_id = m_reportIdVolumeDec_In;
    ioctl(m_iHandle,HIDIOCSUSAGE,&uref);
    ioctl(m_iHandle,HIDIOCSREPORT,&rinfo);

    uref = m_volumeUpEv;
    uref.report_id = m_reportIdVolumeInc_In;
    uref.value = 0;
    rinfo.report_id = m_reportIdVolumeInc_In;
    ioctl(m_iHandle,HIDIOCSUSAGE,&uref);
    ioctl(m_iHandle,HIDIOCSREPORT,&rinfo);
}


//jabra需要在ubuntu下需要回复设备打开led，才会亮灯;而在windows下会自动亮灯
//而plantronics耳机在ubuntu下不需要回复也可以打开led
//而且测试发现主机这边发送led开关给设备，设备也会回复，这时候不用回复设备也可以led亮，但是此时区别不了这个read的触发是因为物理按钮还是UI按钮
//这里还要处理同状态，同状态则忽略
void HidDevice::handleRead()
{
    struct hiddev_usage_ref evs[64];
    int evNum = read(m_iHandle,evs,64*sizeof(hiddev_usage_ref)) / sizeof(hiddev_usage_ref);
    qDebug("evNum:%d",evNum);
    if(evNum < 0){
        qDebug("read error");
        return;
    }
    //OffHook是绝对值，Mute和flash是相对值
    for(int i=0;i<evNum;i++){
        struct hiddev_usage_ref &ev = evs[i];
        qDebug("ev.field_index:%x,ev.report_id:%x,ev.usage_code:%x,ev.usage_index:%x,ev.value:%x,ev.report_type:%x",
               ev.field_index,ev.report_id,ev.usage_code,ev.usage_index,ev.value,ev.report_type);

        if(ev.usage_code == (HID_USAGE_PAGE_TELEPHOY << 16 | HID_USAGE_TELEPHOY_HOOK_SWITCH) && ev.value == !m_stateOffHook){
            invertOffHook();
        }else if(ev.usage_code == (HID_USAGE_PAGE_TELEPHOY << 16 | HID_USAGE_TELEPHOY_MUTE) && ev.value == 1){
            //mute is relative
            invertMute();
        }else if(ev.usage_code == (HID_USAGE_PAGE_TELEPHOY << 16 | HID_USAGE_TELEPHOY_FLASH) && ev.value == 1){
            invertFlash();
        }else if(ev.usage_code == (HID_USAGE_PAGE_CONSUMER << 16 | HID_USAGE_CONSUMER_VOLUME_INCREMENT)){
            if(ev.value == 1){  //测试发现,音量加按钮按下会发送加1减0包，松开会发送加0减0包；音量减同理
                qDebug("volume increase");
                emit sigKeyPress(KEY_VOLUME_INC,0);
                emit sigTimerStart(KEY_VOLUME_INC);
            }else{
                //todo
            }
        }else if(ev.usage_code == (HID_USAGE_PAGE_CONSUMER << 16 | HID_USAGE_CONSUMER_VOLUME_DECREMENT)){
            if(ev.value == 1){
                qDebug("volume decrease");
                emit sigKeyPress(KEY_VOLUME_DEC,0);
                emit sigTimerStart(KEY_VOLUME_DEC);
            }else{
                //todo
            }
        }

    }

}


//send signal only, not change device led state; if need ,repleace func(handleRead) on hidreactor.cpp
void HidDevice::sigRead()
{
    struct hiddev_usage_ref evs[64];
    int evNum = read(m_iHandle,evs,64*sizeof(hiddev_usage_ref)) / sizeof(hiddev_usage_ref);
    qDebug("evNum:%d",evNum);
    if(evNum < 0){
        qDebug("read error");
        return;
    }

    for(int i=0;i<evNum;i++){
        struct hiddev_usage_ref ev = evs[i];
        qDebug("ev.field_index:%x,ev.report_id:%x,ev.usage_code:%x,ev.usage_index:%x,ev.value:%x,ev.report_type:%x",
               ev.field_index,ev.report_id,ev.usage_code,ev.usage_index,ev.value,ev.report_type);

        if(ev.usage_code == (HID_USAGE_PAGE_TELEPHOY << 16 | HID_USAGE_TELEPHOY_HOOK_SWITCH)){
            //hookswitch is absolute
            if(!m_stateOffHook && ev.value==1){
                emit sigKeyPress(KEY_HOOK_SWITCH,m_stateOffHook);
                m_stateOffHook = true;
                emit sigStateChanged(-1);
            }else if(m_stateOffHook && ev.value==0){
                emit sigKeyPress(KEY_HOOK_SWITCH,m_stateOffHook);
                m_stateOffHook = false;
                emit sigStateChanged(-1);
            }
        }
        else if(ev.usage_code == (HID_USAGE_PAGE_TELEPHOY << 16 | HID_USAGE_TELEPHOY_MUTE)){
            //mute is relative
            if(ev.value == 1){
                if(!m_stateMute){
                    qDebug("mute on");
                    emit sigKeyPress(KEY_MUTE,m_stateMute);
                }else{
                    qDebug("mute off");
                    emit sigKeyPress(KEY_MUTE,m_stateMute);
                }
                m_stateMute = !m_stateMute;
                emit sigStateChanged(-1);
            }
        }
        else if(ev.usage_code == (HID_USAGE_PAGE_TELEPHOY << 16 | HID_USAGE_TELEPHOY_FLASH)){
            if(ev.value == 1){
                if(m_stateFlash){
                    qDebug("flash on");
                    emit sigKeyPress(KEY_FLASH,m_stateFlash);
                }else{
                    qDebug("flash off");
                    emit sigKeyPress(KEY_FLASH,m_stateFlash);
                }
                m_stateFlash = !m_stateFlash;
                emit sigStateChanged(-1);
            }
        }else if(ev.usage_code == (HID_USAGE_PAGE_CONSUMER << 16 | HID_USAGE_CONSUMER_VOLUME_INCREMENT)){
            if(ev.value == 1){
                qDebug("volume increase");
                emit sigKeyPress(KEY_VOLUME_INC,0);
                emit sigTimerStart(KEY_VOLUME_INC);
            }
        }else if(ev.usage_code == (HID_USAGE_PAGE_CONSUMER << 16 | HID_USAGE_CONSUMER_VOLUME_DECREMENT)){
            if(ev.value == 1){
                qDebug("volume decrease");
                emit sigKeyPress(KEY_VOLUME_DEC,0);
                emit sigTimerStart(KEY_VOLUME_DEC);
            }
        }

    }

}

void HidDevice::UiClickProc(int role)
{
    struct hiddev_usage_ref uref;
    struct hiddev_report_info rinfo;
    uref.report_type = HID_REPORT_TYPE_OUTPUT;
    rinfo.report_type = HID_REPORT_TYPE_OUTPUT;

    switch(role){
    case 1:         //not work
    case 2:{
//        uref = m_volumeDownEv;
//        uref.report_id = m_reportIdVolumeDec_In;
//        uref.value = role == 2 ? 1 : 0;
//        rinfo.report_id = m_reportIdVolumeDec_In;
//        ioctl(m_iHandle,HIDIOCSUSAGE,&uref);
//        ioctl(m_iHandle,HIDIOCSREPORT,&rinfo);

//        uref = m_volumeUpEv;
//        uref.report_id = m_reportIdVolumeInc_In;
//        uref.value = role == 1 ? 1 : 0;
//        rinfo.report_id = m_reportIdVolumeInc_In;
//        ioctl(m_iHandle,HIDIOCSUSAGE,&uref);
//        ioctl(m_iHandle,HIDIOCSREPORT,&rinfo);
//        sendVolumeEnd();

//        char data[17] = {0};
//        data[0] = m_reportIdVolumeDec_In;
//        data[1] = 0x80;
//        auto res = ioctl(m_iHandle,HIDIOCSOUTPUT(17), data);
//        if(res < 0){
//            qDebug("send failed");
//        }else{
//            qDebug("send success");
//        }
        if(role == 1)
            open_libusb1();
        else
            //read_volume();
            read_devfs();
        break;
    }
    case 3:{
        if(handle){
            libusb_release_interface(handle, 0);
            libusb_attach_kernel_driver(handle, 0);
            libusb_reset_device(handle);    //虚拟拔插
            libusb_close(handle);
            libusb_exit(ctx);
            handle = nullptr;
        }
        break;
    }
    case 4:{
        sendMaxVol();
        break;
    }
    case 5:{
        sendMinVol();
        break;
    }
    default:
        return;
    }
}

const DeviceStatus HidDevice::stateCheck()
{
    const struct DeviceStatus s  ={
        .offhook = m_stateOffHook,
        .mute    = m_stateMute,
        .flash   = m_stateFlash
    };
    return s;
}

//HIDIOCSUSAGE后要跟个HIDIOCSREPORT
//hookswitch都是绝对值，0关闭，1开启；可能会有些值是相对值，即1改变原来状态，0不改变
void HidDevice::sendLED(int role)
{
    struct hiddev_report_info rinfo;
    rinfo.report_type = HID_REPORT_TYPE_OUTPUT;
    if(role == 4){
        //hookswitch是绝对值，0关闭，1开启
        m_stateOffHook = !m_stateOffHook;
        m_ledOffHookEv.value = m_stateOffHook;
        ioctl(m_iHandle,HIDIOCSUSAGE,&m_ledOffHookEv);
        rinfo.report_id = m_reportIdOffHook_Out;
        ioctl(m_iHandle,HIDIOCSREPORT,&rinfo);
        emit sigStateChanged(-1);
        emit sigKeyPress(KEY_HOOK_SWITCH,m_stateOffHook);
    }else if(role ==5){
        if(!m_stateMute){
            qDebug("mute on");
        }else{
            qDebug("mute off");
        }
        m_ledMuteEv.value = m_stateMute ? 0 : 1;
        ioctl(m_iHandle,HIDIOCSUSAGE,&m_ledMuteEv);
        rinfo.report_id = m_reportIdMute_Out;
        ioctl(m_iHandle,HIDIOCSREPORT,&rinfo);
        m_stateMute = !m_stateMute;
        emit sigStateChanged(-1);
        emit sigKeyPress(KEY_MUTE,m_stateMute);
    }else if(role == 3){
        if(m_stateFlash){
            qDebug("flash off");
        }else{
            qDebug("flash on");
        }
        m_ledFlashEv.value = m_stateFlash ? 0 : 1;
        ioctl(m_iHandle,HIDIOCSUSAGE,&m_ledFlashEv);
        rinfo.report_id = m_reportIdFlash_Out;
        ioctl(m_iHandle,HIDIOCSREPORT,&rinfo);
        m_stateFlash = !m_stateFlash;
        emit sigStateChanged(-1);
        emit sigKeyPress(KEY_FLASH,m_stateFlash);
    }
}

void HidDevice::invertOffHook()
{
    struct hiddev_report_info rinfo = {
        .report_type = HID_REPORT_TYPE_OUTPUT,
        .report_id = m_reportIdOffHook_Out
    };

    m_stateOffHook = !m_stateOffHook;
    m_ledOffHookEv.value = m_stateOffHook;

    ioctl(m_iHandle,HIDIOCSUSAGE,&m_ledOffHookEv);
    ioctl(m_iHandle,HIDIOCSREPORT,&rinfo);

    emit sigStateChanged(-1);
    emit sigKeyPress(KEY_HOOK_SWITCH,m_stateOffHook);
}

void HidDevice::invertMute()
{
    struct hiddev_report_info rinfo = {
        .report_type = HID_REPORT_TYPE_OUTPUT,
        .report_id = m_reportIdMute_Out
    };

    m_stateMute = !m_stateMute;
    m_ledMuteEv.value = m_stateMute;

    ioctl(m_iHandle,HIDIOCSUSAGE,&m_ledMuteEv);
    ioctl(m_iHandle,HIDIOCSREPORT,&rinfo);

    emit sigStateChanged(-1);
    emit sigKeyPress(KEY_MUTE,m_stateMute);


    if(m_stateMute){
        qDebug("mute on");
    }else{
        qDebug("mute off");
    }
}

void HidDevice::invertFlash()
{
    struct hiddev_report_info rinfo = {
        .report_type = HID_REPORT_TYPE_OUTPUT,
        .report_id = m_reportIdFlash_Out
    };

    m_stateFlash = !m_stateFlash;
    m_ledFlashEv.value = m_stateFlash;

    ioctl(m_iHandle,HIDIOCSUSAGE,&m_ledFlashEv);
    ioctl(m_iHandle,HIDIOCSREPORT,&rinfo);

    emit sigStateChanged(-1);
    emit sigKeyPress(KEY_FLASH,m_stateFlash);

    if(m_stateFlash){
        qDebug("flash on");
    }else{
        qDebug("flash off");
    }
}

int HidDevice::init_libusb()
{
    int r;
    // 初始化 libusb
    r = libusb_init(&ctx);
    if (r < 0) {
        fprintf(stderr, "libusb init error\n");
        exit(0);
        return 1;
    }

    // 打开设备（VID: 0x047f, PID: 0x430f）
    //0b0e:2303
    handle = libusb_open_device_with_vid_pid(ctx, 0x0b0e, 0x2303);
    if (!handle) {
        fprintf(stderr, "Cannot open device\n");
        libusb_exit(ctx);
        exit(0);
        return 1;
    }

    // 设置 interface，如果需要（Interface 0）
    if(libusb_kernel_driver_active(handle,0)){
        if(libusb_detach_kernel_driver(handle,0) == 0){
            qDebug("设备已解绑");
        }else{
            qDebug("设备解绑失败");
            exit(0);
            return -1;
        }
    }
    r = libusb_claim_interface(handle, 0);
    if(r < 0){
        exit(0);
    }
    return r;
}
enum uac_subclass_code : uint8_t {
    UAC_SUBCLASS_UNDEFINED      = 0x00,
    UAC_SUBCLASS_AUDIOCONTROL   = 0x01,
    UAC_SUBCLASS_AUDIOSTREAMING = 0x02,
    UAC_SUBCLASS_MIDISTREAMING  = 0x03
};
/*
 * USB standard request type
 */
enum usb_request_type {
    REQ_TYPE_IF_SET = 0x21,
    REQ_TYPE_IF_GET = 0xA1,
    REQ_TYPE_EP_SET = 0x22,
    REQ_TYPE_EP_GET = 0xA2
};

/*
 * USB standard request get type
 */
enum usb_request_get {
    REQ_SET_CUR = 0x01,
    REQ_SET_MIN = 0x02,
    REQ_SET_MAX = 0x03,
    REQ_SET_RES = 0x04,
    REQ_GET_CUR = 0x81,
    REQ_GET_MIN = 0x82,
    REQ_GET_MAX = 0x83,
    REQ_GET_RES = 0x84
};
/**
 * Table A-11: Feature Unit Control Selectors
 */
enum uac_feature_unit_selectors {
    MUTE_CONTROL = 0x01,
    VOLUME_CONTROL = 0x02,
    BASS_CONTROL = 0x03,
    MID_CONTROL = 0x04,
    TREBLE_CONTROL = 0x05,
    GRAPHIC_EQUALIZER_CONTROL = 0x06,
    AUTOMATIC_GAIN_CONTROL = 0x07,
    DELAY_CONTROL = 0x08,
    BASS_BOOST_CONTROL = 0x09,
    LOUDNESS_CONTROL = 0x0A
};
int HidDevice::open_libusb()
{
    static libusb_context *context = 0;
    static libusb_device_handle *handle = 0;
    static libusb_device *device = 0;

    static libusb_device **devs = 0;
    static const struct libusb_interface_descriptor *ifdesc = nullptr;
    int errval;
    size_t i = 0;
    static libusb_config_descriptor *configDesc = nullptr;
    if(context)
        goto transfer_data;
    ssize_t num_devs;

    struct libusb_device_descriptor desc;
    unsigned char buffer[256];

    assert(!libusb_init(&context));

    num_devs = libusb_get_device_list(context, &devs);
    if (num_devs < 0) {
        fprintf(stderr, "Error getting device list\n");
        libusb_exit(context);
        return 1;
    }

    for (int i = 0; i < num_devs; ++i) {
        libusb_device *dev = devs[i];
        struct libusb_device_descriptor desc;
        int r = libusb_get_device_descriptor(dev, &desc);
        if (r < 0) {
            fprintf(stderr, "Failed to get device descriptor\n");
            continue;
        }
        if(desc.idVendor == 0x047F && desc.idProduct == 0x430F){
            device = dev;
            break;
        }
    }

    assert(!libusb_get_device_descriptor(device, &desc));
    printf("Vendor ID: %04x\n", desc.idVendor);
    printf("Product ID: %04x\n", desc.idProduct);

    assert(libusb_open(device, &handle) == 0);
    device = libusb_get_device(handle);

    assert(libusb_get_string_descriptor_ascii(handle, desc.iManufacturer, buffer, 256) >= 0);
    printf("Manufacturer: %s\n", buffer);
    assert(libusb_get_string_descriptor_ascii(handle, desc.iProduct, buffer, 256) >= 0);
    printf("Product: %s\n", buffer);
    if (libusb_get_string_descriptor_ascii(handle, desc.iSerialNumber, buffer, 256) >= 0)
        printf("Serial No: %s\n", buffer);
    if(libusb_kernel_driver_active(handle,0)){
        if(libusb_detach_kernel_driver(handle,0) == 0){
            qDebug("设备已解绑");
        }else{
            qDebug("设备解绑失败");
            return -1;
        }
    }
    if(libusb_claim_interface(handle, 0) != 0){
        qDebug("claim failed");
    }

//    int result = libusb_control_transfer(handle, 0b10100001, 0x81, 0x0200, 0x0200, mesg, 2, 500);
//    printf(libusb_error_name(result));
//    printf("%d", result);
    errval = libusb_get_active_config_descriptor(device, &configDesc);
    if (errval != LIBUSB_SUCCESS) {
        errval = libusb_get_config_descriptor(device, 0, &configDesc);
        if (errval != LIBUSB_SUCCESS) {
            qDebug("failed to get config descriptor");
            //throw usb_exception_impl("libusb_get_config_descriptor()", (libusb_error) errval);
        }
    }
    for (; i < configDesc->bNumInterfaces; ++i) {
        auto intf_desc = configDesc->interface[i].altsetting;
        if (intf_desc->bInterfaceClass == LIBUSB_CLASS_AUDIO) {
            qDebug("found AUDIO Class interface, subclass=0x%x, protocol=%d", intf_desc->bInterfaceSubClass, intf_desc->bInterfaceProtocol);
            switch (intf_desc->bInterfaceSubClass) {
            case uac_subclass_code::UAC_SUBCLASS_AUDIOCONTROL:{
                ifdesc = configDesc->interface[i].altsetting;
                break;
            }
                //audiocontrol = parse_audiocontrol(intf_desc);
                break;
            case uac_subclass_code::UAC_SUBCLASS_AUDIOSTREAMING:
//                if (!audiocontrol) {
//                    // we expect the AudioControl interface before any AudioStreaming interfaces
//                    throw invalid_device_exception();
//                }
//                scan_audiostreaming(*audiocontrol, &configDesc->interface[i]);
                break;
            default:
                break;
            }
        }
    }

    //auto route_impl = static_cast<const uac_audio_route_impl&>(route);
transfer_data:
    const int cs = VOLUME_CONTROL;
    const int cn = 0;
    //const int unit = route_impl.entry->sources[0]->unit->bUnitID;
    int16_t data = 0x83fb;
//    int LIBUSB_CALL libusb_control_transfer(libusb_device_handle *dev_handle,
//        uint8_t bmRequestType, uint8_t bRequest, uint16_t wValue, uint16_t wIndex,
//        unsigned char *data, uint16_t wLength, unsigned int timeout);
//    errval = libusb_control_transfer(
//        handle,
//        REQ_TYPE_IF_GET,
//        REQ_GET_CUR,
//        cs << 8 | cn,
//        //unit << 8 | ifdesc->bInterfaceNumber,
//        0x09 << 8 | ifdesc->bInterfaceNumber,
//        (uint8_t*) &data,
//        sizeof(data),
//        0 /* timeout */);
    errval = libusb_control_transfer(
        handle,
        0x21,
        0x01,
        0x02 << 8 | 0x01,
        //unit << 8 | ifdesc->bInterfaceNumber,
        0x02 << 8 | 0x00,
        (uint8_t*) &data,
        sizeof(data),
        0 /* timeout */);
    if (errval < 0)
        qDebug("get_feature_master_volume", (libusb_error)errval);
    else{

        return data;
    }


    libusb_release_interface(handle, 0);
    libusb_attach_kernel_driver(handle, 0);
    libusb_exit(context);
}

int HidDevice::open_libusb1()
{
    if(!handle){
        if(init_libusb() < 0)
            return -1;
    }

send_volumeControl:
    // 构建控制传输参数
    uint8_t bmRequestType = 0x21;  // Host to device | Class | Interface
    uint8_t bRequest = 0x01;       // SET_CUR
    uint16_t wValue = 0x0200;      // Volume Control Selector (0x02), Channel 1 (0x01)
    uint16_t wIndex = 0x0200;      // Entity ID 2, Interface 0
    uint16_t wLength = 2;
    unsigned char data[2] = { 0xeb, 0xfa  }; // -5.0820 dB (little endian)

    // 发送控制传输
    int transferred = libusb_control_transfer(handle,
                                              bmRequestType,
                                              bRequest,
                                              wValue,
                                              wIndex,
                                              data,
                                              wLength,
                                              0); // 1s timeout

    if (transferred < 0) {
        fprintf(stderr, "Control transfer failed: %s\n", libusb_error_name(transferred));
    } else {
        printf("Control transfer success: %d bytes sent\n", transferred);
    }

//    libusb_release_interface(handle, 0);
//    libusb_close(handle);
//    libusb_exit(ctx);
    return 0;
}

void HidDevice::open_hidapi()
{
    //write();
}
#include <linux/usbdevice_fs.h>
#include <errno.h>

void HidDevice::open_devfs()
{
    struct usbdevfs_ctrltransfer ctrl = { 0 };
    //unsigned char data[2] = { 0x83, 0xfb }; // 音量数据（-4.4883 dB）
    unsigned char data[2] = { 0xeb, 0xfa };
    ctrl.bRequestType = 0x21; // Host-to-Device | Class | Interface
    ctrl.bRequest = 0x01;     // SET_CUR
    ctrl.wValue = 0x0201;     // VOLUME_CONTROL | Channel 1
    ctrl.wIndex = 0x0200;     // Entity ID | Interface
    ctrl.wLength = sizeof(data);
    ctrl.data = data;
    //ctrl.timeout = 1000;

    int res = ioctl(m_iHandle, USBDEVFS_CONTROL, &ctrl);
    if (res < 0) {                      //return -1, not work
        perror("ioctl");
        printf("errno = %d\n", errno);  //22->EINVALDATA
    }
}

void HidDevice::read_devfs()
{
    struct usbdevfs_ctrltransfer ctrl = { 0 };
    // 用于读取当前音量值的缓冲区
    unsigned char data[2] = {0};
    int ret = -1;
    ctrl.bRequestType = 0xA1; // Host-to-Device | Class | Interface
    ctrl.bRequest = REQ_GET_CUR;     // SET_CUR
    ctrl.wValue = 0x0201;     // VOLUME_CONTROL | Channel 1
    ctrl.wIndex = 0x0200;     // Entity ID | Interface
    ctrl.wLength = sizeof(data);
    ctrl.data = data;
    ctrl.timeout = 5000;
    ret = ioctl(m_iHandle, USBDEVFS_CONTROL, &ctrl);
    if (ret < 0) {                      //return -1, not work
        perror("ioctl");
        printf("errno = %d\n", errno);  //22->EINVALDATA
    }else if (ret == 2) {
        int16_t vol = (int16_t)(data[1] << 8 | data[0]);
        float db = vol / 256.0f;
        printf("当前音量: %.4f dB (原始值: %d)\n", db, vol);
    }

    memset(data,0,sizeof(data));
    ctrl.bRequest = REQ_GET_MAX;
    ret = ioctl(m_iHandle, USBDEVFS_CONTROL, &ctrl);
    if (ret == 2) {
        int16_t vol = (int16_t)(data[1] << 8 | data[0]);
        float db = vol / 256.0f;
        maxvol[0] = data[0];
        maxvol[1] = data[1];
        printf("设备最大音量: %.4f dB (原始值: %d)\n", db, vol);
    } else {
        printf("errno = %d\n", errno);  //22->EINVALDATA
    }

    memset(data,0,sizeof(data));
    ctrl.bRequest = REQ_GET_MIN;
    ret = ioctl(m_iHandle, USBDEVFS_CONTROL, &ctrl);
    if (ret == 2) {
        int16_t vol = (int16_t)(data[1] << 8 | data[0]);
        float db = vol / 256.0f;
        printf("设备最小音量: %.4f dB (原始值: %d)\n", db, vol);
        minvol[0] = data[0];
        minvol[1] = data[1];
    } else {
        printf("errno = %d\n", errno);  //22->EINVALDATA
    }
}

//plantronics: max 11 min -37
void HidDevice::read_volume()
{
    if(!handle){
        if(init_libusb() < 0){
            qDebug("init libusb failed");
            return;
        }
    }
//    uint8_t bmRequestType = 0x21;  // Host to device | Class | Interface
//    uint8_t bRequest = 0x81;       // GET_CUR
//    uint16_t wValue = 0x0200;      // Volume Control Selector (0x02), Channel 1 (0x01)
//    uint16_t wIndex = 0x0200;      // Entity ID 2, Interface 0
//    uint16_t wLength = 2;
//    unsigned char data[2] = { 0x00, 0x00 }; // -4.4883 dB (little endian)

//    // 发送控制传输
//    int transferred = libusb_control_transfer(handle,
//                                              bmRequestType,
//                                              bRequest,
//                                              wValue,
//                                              wIndex,
//                                              data,
//                                              wLength,
//                                              0); // 1s timeout

    // 用于读取当前音量值的缓冲区
    unsigned char data[2] = {0};
    int ret = libusb_control_transfer(handle,
                                      0xA1,        // bmRequestType: Device to host, Class, Interface
                                      REQ_GET_CUR, // bRequest: GET_CUR
                                      0x0201,      // wValue: Volume control (0x02), Channel 1 (0x01)
                                      0x0200,      // wIndex: Entity ID 2, Interface 0
                                      data,
                                      2,           // wLength
                                      1000);       // timeout ms

    if (ret == 2) {
        int16_t vol = (int16_t)(data[1] << 8 | data[0]);
        float db = vol / 256.0f;
        printf("当前音量: %.4f dB (原始值: %d)\n", db, vol);
    } else {
        fprintf(stderr, "GET_CUR 失败: %s\n", libusb_error_name(ret));
    }

    memset(data,0,sizeof(data));
    ret = libusb_control_transfer(handle,
                                          0xA1,        // bmRequestType: Device to host, Class, Interface
                                          REQ_GET_MAX, // bRequest: GET_CUR
                                          0x0201,      // wValue: Volume control (0x02), Channel 1 (0x01)
                                          0x0200,      // wIndex: Entity ID 2, Interface 0
                                          data,
                                          2,           // wLength
                                          1000);       // timeout ms

    if (ret == 2) {
        int16_t vol = (int16_t)(data[1] << 8 | data[0]);
        float db = vol / 256.0f;
        maxvol[0] = data[0];
        maxvol[1] = data[1];
        printf("设备最大音量: %.4f dB (原始值: %d)\n", db, vol);
    } else {
        fprintf(stderr, "GET_MAX 失败: %s\n", libusb_error_name(ret));
    }

    memset(data,0,sizeof(data));
    ret = libusb_control_transfer(handle,
                                          0xA1,        // bmRequestType: Device to host, Class, Interface
                                          REQ_GET_MIN, // bRequest: GET_CUR
                                          0x0201,      // wValue: Volume control (0x02), Channel 1 (0x01)
                                          0x0200,      // wIndex: Entity ID 2, Interface 0
                                          data,
                                          2,           // wLength
                                          1000);       // timeout ms

    if (ret == 2) {
        int16_t vol = (int16_t)(data[1] << 8 | data[0]);
        float db = vol / 256.0f;
        printf("设备最小音量: %.4f dB (原始值: %d)\n", db, vol);
        minvol[0] = data[0];
        minvol[1] = data[1];
    } else {
        fprintf(stderr, "GET_MAX 失败: %s\n", libusb_error_name(ret));
    }

}

int16_t HidDevice::db2vol(float db)
{
    int16_t vol = db * 256.0f;
    return vol;
}

float HidDevice::vol2db(unsigned char data[2])
{
    int16_t vol = (int16_t)(data[1] << 8 | data[0]);
    float db = vol / 256.0f;
    return db;
}

void HidDevice::handleTimeOut()
{
    if(timer.property("KeyVal") == KEY_VOLUME_INC){
        qDebug("KEY_VOLUME_INC release");
        emit sigKeyRelease(KEY_VOLUME_INC);
    }else if(timer.property("KeyVal") == KEY_VOLUME_DEC){
        qDebug("KEY_VOLUME_DEC release");
        emit sigKeyRelease(KEY_VOLUME_DEC);
    }
    timer.setProperty("KeyVal",KEY_NULL);
}

int HidDevice::setRWFlags()
{
    int flags = HIDDEV_FLAG_UREF | HIDDEV_FLAG_REPORT;
    if(ioctl(m_iHandle,HIDIOCSFLAG,&flags) == -1){
        qDebug("HIDIOCSFLAG error");
        return -1;
    }
    return 1;
}

int HidDevice::sendMaxVol()
{
    if(!handle){
        if(init_libusb() < 0)
            return -1;
    }
    // 构建控制传输参数
    uint8_t bmRequestType = 0x21;  // Host to device | Class | Interface
    uint8_t bRequest = 0x01;       // SET_CUR
    uint16_t wValue = 0x0200;      // Volume Control Selector (0x02), Channel 1 (0x01)
    uint16_t wIndex = 0x0200;      // Entity ID 2, Interface 0
    uint16_t wLength = 2;

    // 发送控制传输
    int transferred = libusb_control_transfer(handle,
                                              bmRequestType,
                                              bRequest,
                                              wValue,
                                              wIndex,
                                              maxvol,
                                              wLength,
                                              0); // 1s timeout

    if (transferred < 0) {
        fprintf(stderr, "Control transfer failed: %s\n", libusb_error_name(transferred));
    } else {
        printf("Control transfer success: %d bytes sent\n", transferred);
    }
    return transferred;
}

int HidDevice::sendMinVol()
{
    if(!handle){
        if(init_libusb() < 0)
            return -1;
    }

    // 构建控制传输参数
    uint8_t bmRequestType = 0x21;  // Host to device | Class | Interface
    uint8_t bRequest = 0x01;       // SET_CUR
    uint16_t wValue = 0x0200;      // Volume Control Selector (0x02), Channel 1 (0x01)
    uint16_t wIndex = 0x0200;      // Entity ID 2, Interface 0
    uint16_t wLength = 2;

    // 发送控制传输
    int transferred = libusb_control_transfer(handle,
                                              bmRequestType,
                                              bRequest,
                                              wValue,
                                              wIndex,
                                              minvol,
                                              wLength,
                                              0); // 1s timeout

    if (transferred < 0) {
        fprintf(stderr, "Control transfer failed: %s\n", libusb_error_name(transferred));
    } else {
        printf("Control transfer success: %d bytes sent\n", transferred);
    }
    return transferred;
}
